package handler

import (
	"context"
	"encoding/json"

	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"google.golang.org/protobuf/types/known/emptypb"

	"mxshop_srvs/goods_srv/model"
	proto "mxshop_srvs/goods_srv/proto/gen/v1"
)

func categoryModelToProto(categories []model.Category) []*proto.CategoryListInfo {
	var data []*proto.CategoryListInfo
	for _, category := range categories {
		data = append(data, &proto.CategoryListInfo{
			Id:             category.ID,
			Name:           category.Name,
			ParentCategory: category.ParentCategoryID,
			Level:          category.Level,
			IsTab:          category.IsTab,
			Subcategory:    categoryModelToProto(category.SubCategory),
		})
	}
	return data
}

func (s *Service) GetAllCategoryList(_ context.Context, _ *emptypb.Empty) (*proto.CategoryListResponse, error) {
	total, err := s.DB.GetCategoryCount()
	if err != nil {
		return nil, status.Error(codes.Internal, "")
	}
	categories, err := s.DB.CategoryList()
	if err != nil {
		return nil, status.Error(codes.Internal, "")
	}
	// strCh := make(chan string, 1)
	// go func(v interface{}, stringCh chan string) {
	// 	b, _ := json.Marshal(v)
	// 	stringCh <- string(b)
	// }(categories, strCh)
	b, err := json.Marshal(categories)
	if err != nil {
		return nil, status.Error(codes.Internal, "")
	}

	data := categoryModelToProto(categories)
	return &proto.CategoryListResponse{
		Total: int32(total),
		// JsonData:      <-strCh,
		JsonData:      string(b),
		Subcategories: data,
	}, nil
}

func (s *Service) GetSubCategory(_ context.Context, req *proto.CategoryListRequest) (*proto.SubCategoryListResponse, error) {
	category, err := s.DB.GetCategory(req.Id)
	if err != nil {
		return nil, status.Error(codes.NotFound, "")
	}

	categories, err := s.DB.GetSubCategories(req.Id)
	if err != nil {
		return nil, status.Error(codes.Internal, "")
	}

	var subcategories []*proto.CategoryInfoResponse
	for _, category := range categories {
		subcategories = append(subcategories, &proto.CategoryInfoResponse{
			Id:             category.ID,
			Name:           category.Name,
			ParentCategory: category.ParentCategoryID,
			Level:          category.Level,
			IsTab:          category.IsTab,
		})
	}

	return &proto.SubCategoryListResponse{
		Total: int32(len(categories)),
		Info: &proto.CategoryInfoResponse{
			Id:             category.ID,
			Name:           category.Name,
			ParentCategory: category.ParentCategoryID,
			Level:          category.Level,
			IsTab:          category.IsTab,
		},
		SubCategory: subcategories,
	}, nil
}

func (s *Service) CreateCategory(_ context.Context, req *proto.CategoryInfoRequest) (*proto.CategoryInfoResponse, error) {
	if req.Level > 1 {
		ok, err := s.DB.IsCategoryExists(req.ParentCategory)
		if err != nil {
			return nil, status.Error(codes.Internal, "")
		}
		if !ok {
			return nil, status.Error(codes.InvalidArgument, "category_id: must be filled in correctly")
		}
	}

	categoryID, err := s.DB.CreateCategory(req)
	if err != nil {
		return nil, status.Error(codes.Internal, "")
	}
	return &proto.CategoryInfoResponse{
		Id: categoryID,
	}, nil
}

func (s *Service) DeleteCategory(_ context.Context, req *proto.DeleteCategoryRequest) (*emptypb.Empty, error) {
	_, err := s.DB.GetCategory(req.Id)
	if err != nil {
		return nil, status.Error(codes.NotFound, "")
	}

	rows, err := s.DB.DeleteCategory(req.Id)
	if err != nil || rows == 0 {
		return nil, status.Error(codes.Internal, "")
	}

	return &emptypb.Empty{}, nil
}

func (s *Service) UpdateCategory(_ context.Context, req *proto.CategoryInfoRequest) (*emptypb.Empty, error) {
	category, err := s.DB.GetCategory(req.Id)
	if err != nil {
		return nil, status.Error(codes.NotFound, "")
	}

	_, i, err := s.DB.UpdateCategory(category, req)
	if err != nil {
		return nil, status.Error(codes.Internal, "")
	}
	if i == 0 {
		return nil, status.Error(codes.Internal, "")
	}
	return &emptypb.Empty{}, nil
}
